package com.black.utils.network.app.http;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.black.protocol.Response;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;

/**
 * Restful 风格请求工具类
 *
 * @author ylx
 */
@Slf4j
public class RestfulUtil {
    public static final String GET = "GET";
    public static final String POST = "POST";

    /**
     * Get 请求
     * 与使用当前相同protocol协议的服务通讯
     *
     * @param clazz   返回类型
     * @param url     请求地址
     * @param headers 请求头
     * @param params  请求参数
     * @param <T>     泛型
     * @return 同protocol协议下的 Response 对象
     */
    public static <T> Response<T> get(Class<T> clazz, String url, Map<String, Object> headers, Map<String, Object> params) {
        String response = get(url, headers, params);
        return getResult(response, clazz);
    }

    /**
     * Get 请求
     * 与任意服务通讯
     *
     * @param clazz   返回类型
     * @param url     请求地址
     * @param headers 请求头
     * @param params  请求参数
     * @param <T>     泛型
     * @return 指定类型对象
     */
    public static <T> T get(String url, Map<String, Object> headers, Map<String, Object> params, Class<T> clazz) {
        String response = get(url, headers, params);
        if (response == null) {
            log.error("url: {} result is null", url);
            return null;
        }
        return JSONObject.parseObject(response, clazz);
    }

    /**
     * Get 请求
     * 与任意服务通讯
     *
     * @param url     请求地址
     * @param headers 请求头
     * @param params  请求参数
     * @return 返回字符串
     */
    public static String get(String url, Map<String, Object> headers, Map<String, Object> params) {
        if (!url.contains("?")) {
            url = url + "?";
        } else {
            url = url + "&";
        }
        if (params != null) {
            StringBuilder urlBuilder = new StringBuilder(url);
            for (String key : params.keySet()) {
                urlBuilder.append(key).append("=").append(params.get(key)).append("&");
            }
            url = urlBuilder.deleteCharAt(url.length() - 1).toString();
        }
        try {
            URL URL = new URL(url);
            HttpURLConnection connection = (HttpURLConnection) URL.openConnection();
            connection.setRequestMethod(GET);
            setRequestProperties(connection, headers);
            return getResponse(connection, url);
        } catch (MalformedURLException e) {
            log.error("url: {} is invalid", url);
        } catch (IOException e) {
            log.error("url: {} request error", url);
        }
        return null;
    }

    /**
     * Post 请求
     * 与当前相同protocol协议的服务通讯
     *
     * @param clazz   返回类型
     * @param url     请求地址
     * @param headers 请求头
     * @param body    请求体
     * @param <T>     泛型
     * @return 同protocol协议下的 Response 对象
     */
    public static <T> Response<T> post(Class<T> clazz, String url, Map<String, Object> headers, JSONObject body) {
        String response = post(url, headers, body);
        return getResult(response, clazz);
    }

    /**
     * Post 请求
     * 与任意服务通讯
     *
     * @param clazz   返回类型
     * @param url     请求地址
     * @param headers 请求头
     * @param body    请求体
     * @param <T>     泛型
     * @return 指定类型对象
     */
    public static <T> T post(String url, Map<String, Object> headers, JSONObject body, Class<T> clazz) {
        String response = post(url, headers, body);
        if (response == null) {
            log.error("url: {} result is null", url);
            return null;
        }
        return JSONObject.parseObject(response, clazz);
    }

    /**
     * Post 请求
     * 与任意服务通讯
     *
     * @param url     请求地址
     * @param headers 请求头
     * @param body    请求体
     * @return 返回字符串
     */
    public static String post(String url, Map<String, Object> headers, JSONObject body) {
        try {
            URL URL = new URL(url);
            HttpURLConnection connection = (HttpURLConnection) URL.openConnection();
            connection.setRequestMethod(POST);
            setRequestProperties(connection, headers);
            if (body != null) {
                connection.setDoOutput(true);
                connection.getOutputStream().write(body.toJSONString().getBytes());
            }
            return getResponse(connection, url);
        } catch (MalformedURLException e) {
            log.error("url: {} is invalid", url);
        } catch (IOException e) {
            log.error("url: {} request error", url);
        }
        return null;
    }

    /**
     * 设置请求头
     *
     * @param connection http连接
     * @param headers    请求头
     */
    private static void setRequestProperties(HttpURLConnection connection, Map<String, Object> headers) {
        if (headers != null) {
            headers.forEach((k, v) -> connection.setRequestProperty(k, v.toString()));
        }
        connection.setConnectTimeout(5000);
        connection.setReadTimeout(5000);
        connection.setRequestProperty("Content-Type", "application/json");
        connection.setRequestProperty("Accept", "application/json");
        connection.setRequestProperty("Connection", "keep-alive");
        connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/92.0.4515.159 Safari/537.36");
    }

    /**
     * 获取响应
     *
     * @param connection http连接
     * @param url        请求地址
     * @return 响应字符串
     * @throws IOException IO异常
     */
    private static String getResponse(HttpURLConnection connection, String url) throws IOException {
        int responseCode = connection.getResponseCode();
        if (responseCode == HttpURLConnection.HTTP_OK) {
            BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String inputLine;
            StringBuilder response = new StringBuilder();

            while ((inputLine = in.readLine()) != null) {
                response.append(inputLine);
            }
            in.close();
            return response.toString();
        } else {
            log.error("url: {},responseCode: {}", url, responseCode);
        }
        return null;
    }

    /**
     * 获取响应结果
     *
     * @param responseStr 响应字符串
     * @param clazz       返回类型
     * @param <T>         泛型
     * @return Response 对象
     */
    private static <T> Response<T> getResult(String responseStr, Class<T> clazz) {
        if (responseStr == null) {
            return Response.response(-1, "response is null", null);
        }
        Response<?> response = JSONObject.parseObject(responseStr, Response.class);
        if (response.getCode() == 0) {
            return Response.success(JSON.parseObject(response.getRes().toString(), clazz));
        } else {
            return Response.fail();
        }
    }
}

